using System; using ExternPropertyAttributes; using UnityEngine; using UnityEngine.Rendering.Universal; using Debug = UnityEngine.Debug; // ReSharper disable RedundantDefaultMemberInitializer #if UNITY_2022_3_OR_NEWER namespace FlatKit { [CreateAssetMenu(fileName = "OutlineSettings", menuName = "FlatKit/Outline Settings")] public class OutlineSettings : ScriptableObject { [Space] // Expandable. [Tooltip("The color of the lines. Alpha is used for transparency, " + "0 means fully transparent and 1 means fully opaque lines.")] public Color edgeColor = Color.white; [Range(0, 5)] [Tooltip("The width of the lines in screen space. If 'Resolution Invariant' is disabled, " + "this is the width in pixels. Otherwise, it is a relative width.")] public int thickness = 1; [Tooltip("If enabled, the line width will stay constant regardless of the rendering resolution. " + "However, some of the lines may appear blurry.")] public bool resolutionInvariant = false; [Tooltip("If enabled, the outline will become more transparent the further away it is from the camera.")] public bool fadeWithDistance = false; [ShowIf(nameof(fadeWithDistance))] [Label(" Start")] [Tooltip("The distance from the camera at which the outline starts to fade. The value is in world units.")] public float fadeRangeStart = 10f; [ShowIf(nameof(fadeWithDistance))] [Label(" End")] [Tooltip("The distance from the camera at which the outline is fully transparent. The value is in world units.")] public float fadeRangeEnd = 50f; [HorizontalLine] [Tooltip("Whether to use depth information to draw outlines. This adds lines around objects that are in front of " + "other objects.")] public bool useDepth = true; [ShowIf(nameof(useDepth))] [Label(" Min Threshold")] [Min(0)] [Tooltip("Minimum distance between two pixels to be considered an edge. The outline is drawn almost transparent.")] public float minDepthThreshold = 0.1f; [ShowIf(nameof(useDepth))] [Label(" Max Threshold")] [Min(0)] [Tooltip("Maximum distance between two pixels to be considered an edge. The outline is drawn fully opaque.")] public float maxDepthThreshold = 0.25f; [HorizontalLine(1, EColor.Translucent)] [Tooltip("Whether to use world-space normals information to draw outlines. This adds lines " + "on sharp edges of objects.")] public bool useNormals = false; [ShowIf(nameof(useNormals))] [Label(" Min Threshold")] [Min(0)] [Tooltip("Minimum angle between two normals to be considered an edge. The outline is drawn almost transparent.")] public float minNormalsThreshold = 0.1f; [ShowIf(nameof(useNormals))] [Label(" Max Threshold")] [Min(0)] [Tooltip("Maximum angle between two normals to be considered an edge. The outline is drawn fully opaque.")] public float maxNormalsThreshold = 0.25f; [HorizontalLine(1, EColor.Translucent)] [Tooltip("Whether to use color information to draw outlines. This adds lines where the color of the object " + "changes.")] public bool useColor = false; [ShowIf(nameof(useColor))] [Label(" Min Threshold")] [Min(0)] [Tooltip("Minimum difference in color between two pixels to be considered an edge. The outline is drawn almost " + "transparent.")] public float minColorThreshold = 0.1f; [ShowIf(nameof(useColor))] [Label(" Max Threshold")] [Min(0)] [Tooltip("Maximum difference in color between two pixels to be considered an edge. The outline is drawn fully " + "opaque.")] public float maxColorThreshold = 0.25f; [HorizontalLine] [Tooltip("The render stage at which the effect is applied. To exclude transparent objects, like water or UI " + "elements, set this to \"Before Transparent\".")] public RenderPassEvent renderEvent = RenderPassEvent.BeforeRenderingPostProcessing; [Tooltip("Only draw the outline, replacing the original color with a complimentary color.")] public bool outlineOnly = false; [Tooltip("Whether the effect should be applied in the Scene view as well as in the Game view. Please keep in " + "mind that Unity always renders the scene view with the default Renderer settings of the URP config.")] public bool applyInSceneView = true; [HideInInspector] public Material effectMaterial; internal Action onSettingsChanged; internal Action onReset; private void OnValidate() { if (minDepthThreshold > maxDepthThreshold + float.Epsilon) { Debug.LogWarning("[Flat Kit] Outline configuration error: 'Min Depth Threshold' must not " + "be greater than 'Max Depth Threshold'"); } if (minNormalsThreshold > maxNormalsThreshold + float.Epsilon) { Debug.LogWarning("[Flat Kit] Outline configuration error: 'Min Normals Threshold' must not " + "be greater than 'Max Normals Threshold'"); } if (minColorThreshold > maxColorThreshold + float.Epsilon) { Debug.LogWarning("[Flat Kit] Outline configuration error: 'Min Color Threshold' must not " + "be greater than 'Max Color Threshold'"); } fadeRangeStart = Mathf.Max(0f, Mathf.Min(fadeRangeStart, fadeRangeEnd)); fadeRangeEnd = Mathf.Max(fadeRangeStart, Mathf.Min(fadeRangeEnd, 1000f)); onSettingsChanged?.Invoke(); } private void Reset() { onReset?.Invoke(); } private void OnDestroy() { onSettingsChanged = null; onReset = null; } } } #else namespace FlatKit { [CreateAssetMenu(fileName = "OutlineSettings", menuName = "FlatKit/Outline Settings")] public class OutlineSettings : ScriptableObject { public Color edgeColor = Color.white; [Range(0, 5)] public int thickness = 1; [Tooltip("If enabled, the line width will stay constant regardless of the rendering resolution. " + "However, some of the lines may appear blurry.")] public bool resolutionInvariant = false; [Space] public bool useDepth = true; public bool useNormals = false; public bool useColor = false; [Header("Advanced settings")] public float minDepthThreshold = 0f; public float maxDepthThreshold = 0.25f; [Space] public float minNormalsThreshold = 0f; public float maxNormalsThreshold = 0.25f; [Space] public float minColorThreshold = 0f; public float maxColorThreshold = 0.25f; [Space, Tooltip("The render stage at which the effect is applied. To exclude transparent objects, " + "like water or UI elements, set this to \"Before Transparent\".")] public RenderPassEvent renderEvent = RenderPassEvent.BeforeRenderingPostProcessing; public bool outlineOnly = false; [Tooltip("Whether the effect should be applied in the Scene view as well as in the Game view. Please keep in " + "mind that Unity always renders the scene view with the default Renderer settings of the URP config.")] public bool applyInSceneView = true; private void OnValidate() { if (minDepthThreshold > maxDepthThreshold + float.Epsilon) { Debug.LogWarning("[Flat Kit] Outline configuration error: 'Min Depth Threshold' must not " + "be greater than 'Max Depth Threshold'"); } if (minNormalsThreshold > maxNormalsThreshold + float.Epsilon) { Debug.LogWarning("[Flat Kit] Outline configuration error: 'Min Normals Threshold' must not " + "be greater than 'Max Normals Threshold'"); } if (minColorThreshold > maxColorThreshold + float.Epsilon) { Debug.LogWarning("[Flat Kit] Outline configuration error: 'Min Color Threshold' must not " + "be greater than 'Max Color Threshold'"); } } } } #endif